package com.yexiao.cofe.util;

import org.springframework.stereotype.Component;

import java.util.Calendar;
import java.util.Random;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

/**
 * 取餐码生成器
 *
 * @author lkl
 * @since 2025/4/2
 */
@Component
public class PickCodeGenerator {

    // 存储每个门店取餐码计数器计数器
    private final ConcurrentHashMap<String, Integer> codeMap = new ConcurrentHashMap<>();

    // 每个门店维护一把锁
    private final ConcurrentHashMap<String, Lock> storeLockMap = new ConcurrentHashMap<>();

    private final Random random = new Random();

    {
        // 定时任务，每天0点刷新计数器
        ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1);
        Calendar calendar = Calendar.getInstance();
        calendar.set(Calendar.HOUR_OF_DAY, 0);
        calendar.set(Calendar.MINUTE, 0);
        calendar.set(Calendar.SECOND, 0);
        calendar.set(Calendar.MILLISECOND, 0);
        if (calendar.getTimeInMillis() < System.currentTimeMillis()) {
            calendar.add(Calendar.DAY_OF_YEAR, 1);
        }
        long initialDelay = calendar.getTimeInMillis() - System.currentTimeMillis();
        scheduler.scheduleAtFixedRate(() -> {
            // 清除前一天的取餐码缓存
            codeMap.clear();
            storeLockMap.clear();
        }, initialDelay, TimeUnit.DAYS.toMillis(1), TimeUnit.MILLISECONDS);
    }

    private int getRandomCode() {
        // 10 ~ 80 随机数
        int code = random.nextInt(70);
        code += 10;
        code *= 100;
        code += 1;
        return code;
    }

    /**
     * 获取取餐码
     */
    public int getNextCode(String storeId) {
        Lock lock = storeLockMap.getOrDefault(storeId, new ReentrantLock());
        lock.lock();

        Integer code = codeMap.getOrDefault(storeId, getRandomCode());
        codeMap.put(storeId, code+1);

        lock.unlock();
        return code;
    }

}
